package cn.wit.sst.service;

import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.wit.sst.domain.Course;
import cn.wit.sst.domain.Major;
import cn.wit.sst.domain.Student;
import cn.wit.sst.dto.ScoreRankDto;
import cn.wit.sst.dto.StudentDto;
import cn.wit.sst.mapper.ScoreMapper;
import cn.wit.sst.mapper.StudentMapper;
import cn.wit.sst.utils.AppCache;
import cn.wit.sst.utils.Utils;

@Service
@Transactional
public class StudentService {
	@Autowired
	StudentMapper studentMapper;

	@Autowired
	ScoreMapper scoreMapper;

	@Autowired
	AppCache cache;

	public Student selectBySno(Long sno) {
		return studentMapper.selectByNo(sno);
	}

	/**
	 *	根据学号，查询学生四年的考试成绩
	 */
	public StudentDto queryAllScores(Long sno) {
		// 获取正在查询的学生信息
		Student s = studentMapper.selectByNo(sno);

		// 获取某个学生四年（八个学期）的成绩
		List<ScoreRankDto> allScores = scoreMapper.getAllScoreRanksForClazz(s.getMid(),
				s.getYear(), s.getClazz());

		// 按学期分组 (key:学期，value:所有学生各课程分数)
		Map<String, List<ScoreRankDto>> scoresBySemester = allScores.stream()
			.collect(Collectors.groupingBy(new Function<ScoreRankDto, String>() {
				@Override
				public String apply(ScoreRankDto t) {
					return t.getStartYear() + "-" + t.getSemester();
				}
			}));

		// 对每个学期的分数进行排名和统计
		List<ScoreRankDto> results = scoresBySemester.entrySet().stream()
			.map(entry -> {
				return rankBySemester(entry.getValue(), s);
			})
			.flatMap(list -> list.stream())
			.collect(Collectors.toList());

		StudentDto dto = toStudentDto(s);
		dto.setScores(results);

		return dto;
	}

	// 返回学生某一学期的排名信息（包括总分）
	private List<ScoreRankDto> rankBySemester(List<ScoreRankDto> clazzScores, Student s) {
		// 总分计算
		Map<Long, DoubleSummaryStatistics> sumaryScores = clazzScores.stream()
				.collect(Collectors.groupingBy(ScoreRankDto::getSid, // 按sid（学生）进行分组
						Collectors.summarizingDouble(ScoreRankDto::getScore)) // 对分数求和
		); // map里面key为学生id、value为总分统计

		// 总分排序
		List<ScoreRankDto> sumaryScoresRanked = sumaryScores.entrySet().stream().map(e -> {
			ScoreRankDto dto = new ScoreRankDto();
			dto.setCid(0L); // 0不代表任何课程，专用于总分显示
			dto.setCourse("总分");
			dto.setScore((float) e.getValue().getSum());
			dto.setSid(e.getKey());
			return dto;
		}).sorted((left, right) -> {
			return right.getScore().compareTo(left.getScore()); // 由高到低
		}).collect(Collectors.toList());

		clazzScores.addAll(sumaryScoresRanked); // 将总分当成一个单独的“课程”，加入到班级分数列表

		// 将各课程分数分组 （key为课程id，value为所有学生该课程的分数集合）
		Map<Long, List<ScoreRankDto>> map = clazzScores.stream().collect(Collectors.groupingBy(ScoreRankDto::getCid));

		// 遍历每一学科，计算排名
		map.forEach((key, value) -> {
			Utils.computeRank(value);
		});

		// 获取当前学生每个课程的排名
		List<ScoreRankDto> scoreResults = clazzScores.stream().filter(item -> {
			return item.getSid().equals(s.getId()); // 只取当前查询学生的排名分数
		}).map(item -> {
			Course c = cache.getCourse(item.getCid()); // 根据课程id设置课程名

			if (c != null) {
				item.setCourse(c.getName());
			}

			// 设置学期信息
			if (item.getStartYear() != null
					&& item.getSemester() != null) {

				String displaySemester = getDisplaySemester(
						item.getStartYear() - s.getYear(), item.getSemester());
				item.setDisplaySemester(displaySemester);
			}

			return item;
		}).collect(Collectors.toList());

		return scoreResults;
	}

	private String getDisplaySemester(int year, Byte semester) {
		String[] YEARS = {"大一", "大二", "大三", "大四"};
		String[] SEMESTERS = {"（上）", "（下）"};

		return YEARS[year] + SEMESTERS[semester - 1];
	}

	private StudentDto toStudentDto(Student s) {
		StudentDto dto = new StudentDto();
		dto.setName(s.getName());
		dto.setYear(s.getYear());
		dto.setSno(s.getSno());
		dto.setClazz(s.getClazz());

		// 从缓存读取专业名字
		Major major = cache.getMajor(s.getMid());
		if (major != null) {
			dto.setMajor(major.getName());
		}

		return dto;
	}
}
